package com.itlong.cloud.controller.property;

import com.itlong.cloud.POJO.DTO.property.*;
import com.itlong.cloud.POJO.VO.MessageVO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectBuildInfoVO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectRoomInfoVO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectUnitInfoVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.abstracts.BaseController;
import com.itlong.cloud.annotation.AuthAccessRequired;
import com.itlong.cloud.annotation.LoggerInfo;
import com.itlong.cloud.constants.LogDescConstant;
import com.itlong.cloud.enumerate.FileCatalogEnum;
import com.itlong.cloud.enumerate.ImportAddressOperationType;
import com.itlong.cloud.enumerate.LiftDoorTypeEnum;
import com.itlong.cloud.enumerate.ecode.BaseErrorCodeEnum;
import com.itlong.cloud.enumerate.ecode.ErrorCode;
import com.itlong.cloud.enumerate.ecode.PropertyErrorCodeEnum;
import com.itlong.cloud.project.property.IPropertyAddressInfoServiceClient;
import com.itlong.cloud.project.property.IPropertyBuildInfoServiceClient;
import com.itlong.cloud.project.property.IPropertyRoomInfoServiceClient;
import com.itlong.cloud.project.property.IPropertyUnitInfoServiceClient;
import com.itlong.cloud.thrown.DataAccessException;
import com.itlong.cloud.utils.export.ExportUtil;
import com.itlong.cloud.utils.file.UploadFileUtil;
import com.itlong.cloud.utils.network.http.HttpProtocolUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.words.NumberHandlerUtil;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * <desc>
 *      地址信息管理控制器（如导入、导出）
 * </desc>
 *
 * @createDate 2017-09-21
 */
@RestController
@RequestMapping("project/addressInfo")
@RefreshScope
public class PropertyAddressInfoController extends BaseController {

    private static Logger LOG = LoggerFactory.getLogger(PropertyAddressInfoController.class);

    @Value("${" + PlatformConstants.FILE_FTP_HOST + "}")
    public String FILE_FTP_HOST;

    @Value("${" + PlatformConstants.FILE_FTP_PORT + "}")
    public String FILE_FTP_PORT;

    @Value("${" + PlatformConstants.FILE_FTP_USERNAME + "}")
    public String FILE_FTP_USERNAME;

    @Value("${" + PlatformConstants.FILE_FTP_PASSWORD + "}")
    public String FILE_FTP_PASSWORD;

    @Value("${" + PlatformConstants.FILE_ACCESS_URL + "}")
    public String FILE_ACCESS_URL;

    @Value("${" + PlatformConstants.PROJECT_STATIC_FILE_PATH + "}")
    public String PROJECT_STATIC_FILE_PATH;


    private final
    IPropertyAddressInfoServiceClient iPropertyAddressInfoServiceClient;   //地址信息服务接口协议提供对象.

    private final
    IPropertyBuildInfoServiceClient iPropertyBuildInfoServiceClient; //楼栋信息服务接口协议提供对象.

    private final
    IPropertyUnitInfoServiceClient iPropertyUnitInfoServiceClient; //单元信息服务接口协议提供对象

    private final
    IPropertyRoomInfoServiceClient iPropertyRoomInfoServiceClient; //房屋信息服务接口协议提供对象

    @Autowired
    public PropertyAddressInfoController(IPropertyAddressInfoServiceClient iPropertyAddressInfoServiceClient,
                                         IPropertyBuildInfoServiceClient iPropertyBuildInfoServiceClient,
                                         IPropertyUnitInfoServiceClient iPropertyUnitInfoServiceClient,
                                         IPropertyRoomInfoServiceClient iPropertyRoomInfoServiceClient) {
        this.iPropertyAddressInfoServiceClient = iPropertyAddressInfoServiceClient;
        this.iPropertyBuildInfoServiceClient = iPropertyBuildInfoServiceClient;
        this.iPropertyUnitInfoServiceClient = iPropertyUnitInfoServiceClient;
        this.iPropertyRoomInfoServiceClient = iPropertyRoomInfoServiceClient;
    }

    /**
     * <desc>
     *      获取地址导出模板文件下载链接
     * </desc>
     *
     * @return MessageVO 标准格式化响应结果
     * @author LouisLewis
     * @createDate 2017-10-11
     */
    @LoggerInfo(operateDesc = LogDescConstant.GET_EXCEL_TEMPLATE_URL_LOG_DESC)
    @RequestMapping(path = "getExcelTemplateUrl", method = RequestMethod.POST)
    @ResponseBody
    @AuthAccessRequired
    public Object getExcelTemplateUrl() {
        MessageVO messageVO;
        try {
            String templateFilePath = FILE_ACCESS_URL + FileCatalogEnum.PROJECT_STATIC_FILE.getType()
                    + PlatformConstants.ADDRESS_IMPORT_EXPORT_FILE;
            URI excelTemplateDownLoadUrl = new URI(templateFilePath);

            messageVO = new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode(), (Object) excelTemplateDownLoadUrl.toString());
        } catch (Exception e) {
            throw new DataAccessException("【物业_项目_地址导出模板文件】下载地址导出模板文件失败", e);
        }
        return messageVO;
    }


    /**
     * <desc>
     *      导出地址文件
     * </desc>
     *
     * @param propertyProjectImportAddressExtraDataDTO 从Excel(*.xls)导入地址时附加信息数据传输对象（主要是项目编号ProjectId）
     * @return MessageVO 标准格式化响应结果
     * @author LouisLewis
     * @createDate 2017-10-11
     */
    @LoggerInfo(operateDesc = LogDescConstant.EXPORT_ADDRESS_LOG_DESC)
    @RequestMapping(path = "exportAddresses", method = RequestMethod.POST)
    @ResponseBody
    @AuthAccessRequired
    public Object exportAddresses(PropertyProjectExportAddressesDTO propertyProjectImportAddressExtraDataDTO) {
        MessageVO messageVO;
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            propertyProjectImportAddressExtraDataDTO = HttpProtocolUtil.parseRequestParamToDTO(PropertyProjectExportAddressesDTO.class, request);

            //判断参数合法性
            if (null == propertyProjectImportAddressExtraDataDTO) {
                return new MessageVO(BaseErrorCodeEnum.NOT_PARAM.getErrorCode());
            }

            //楼栋编号不能为空
            if ((StringUtils.isBlank(propertyProjectImportAddressExtraDataDTO.getBuildIds()))) {
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_BUILD_ID_EMPTY_ERR.getErrorCode());
            }

            Path excelFilePath = Paths.get(PROJECT_STATIC_FILE_PATH, PlatformConstants.ADDRESS_IMPORT_EXPORT_FILE);
            //LOG.info("导出房屋模板文件路径 excelFilePath：" + excelFilePath);
            if (!new File(excelFilePath.toString()).exists()) {  //模板文件不存在
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_TMPLATE_FILE_PATH_NOT_EXISTS_ERR.getErrorCode());
            }

            //查询数据库中的房间信息
            List<PropertyProjectRoomInfoVO> propertyProjectRoomInfoVOS = iPropertyAddressInfoServiceClient.getExportAddressInfo(propertyProjectImportAddressExtraDataDTO);
            //没有房屋信息，不用导出
            if (propertyProjectRoomInfoVOS.isEmpty()) {
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_NO_ROOM_INFO_ERR.getErrorCode());
            }
            //创建Excel操作对象，07之前版本(*.xls)使用HSSFWorkBook 07之后版本使用（*.xlsx）XSSFWorkbook
            try (InputStream excelFileStream = new FileInputStream(excelFilePath.toString())) {

                try (HSSFWorkbook workbook = new HSSFWorkbook(excelFileStream)) {
                    HSSFSheet sheet = workbook.getSheetAt(0);
                    short rowHeght = 420;
                    //移除模板中可能存在的样例数据
                    for (int rowIndex = 1; rowIndex <= 3; rowIndex++) {
                        HSSFRow row = sheet.getRow(rowIndex);
                        rowHeght = row.getHeight();
                        sheet.removeRow(row);
                    }

                    for (int roomIndex = 0; roomIndex < propertyProjectRoomInfoVOS.size(); roomIndex++) {
                        PropertyProjectRoomInfoVO propertyProjectRoomInfoVO = propertyProjectRoomInfoVOS.get(roomIndex);
                        int rowIndex = roomIndex + 1; //标题行
                        HSSFRow dataRow = sheet.createRow(rowIndex);
                        dataRow.setHeight(rowHeght);
                        HSSFCell noteCell = dataRow.createCell(0);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getBuildName());
                        noteCell = dataRow.createCell(1);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getBuildNum());
                        noteCell = dataRow.createCell(2);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getUnitName());
                        noteCell = dataRow.createCell(3);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getUnitNum());
                        noteCell = dataRow.createCell(4);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getUnitAlias());
                        noteCell = dataRow.createCell(5);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getRoomNum());
                        noteCell = dataRow.createCell(6);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getBuiltArea());
                        noteCell = dataRow.createCell(7);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getRoomAlias());
                        noteCell = dataRow.createCell(8);
                        noteCell.setCellValue(LiftDoorTypeEnum.getDescription(propertyProjectRoomInfoVO.getLiftDoorType()));
                        noteCell = dataRow.createCell(9);
                        noteCell.setCellValue(propertyProjectRoomInfoVO.getRemark());

                        //Excel格式保护密码
//                        sheet.protectSheet("itlong");
                    }
                    String fileName = String.format("%s_AddressInfo_%s.xls",
                            propertyProjectImportAddressExtraDataDTO.getProjectId(),
                            DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));
                    fileName = URLEncoder.encode(fileName, "UTF-8");


                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    workbook.write(os);
                    byte[] content = os.toByteArray();
                    InputStream exportFileStream = new ByteArrayInputStream(content);
                    String exportfileUrl = uploadFile(exportFileStream,fileName);
                    if (StringUtils.isBlank(exportfileUrl)){
                        return new MessageVO(PropertyErrorCodeEnum.PROJECT_EXPORT_FILE_SAVE_ERR.getErrorCode());
                    }
                    messageVO = new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode(), (Object) exportfileUrl);
                }
            }


        } catch (Exception e) {
            throw new DataAccessException("【物业_项目_导出地址信息】导出地址信息失败", e);
        }
        return messageVO;
    }

    /**
     * <desc>
     *      导入地址文件
     * </desc>
     *
     * @param projectId          项目编号）
     * @param httpServletRequest http请求对象
     * @return MessageVO 标准格式化响应结果
     * @author LouisLewis
     * @createDate 2017-10-11
     */
    @LoggerInfo(operateDesc = LogDescConstant.IMPORT_ADDRESS_LOG_DESC)
    @RequestMapping(path = "importAddresses", method = RequestMethod.POST)
    @ResponseBody
    @AuthAccessRequired
    public Object importAddresses(String projectId,
                                     HttpServletRequest httpServletRequest) {
        //System.out.println(String.format("【%s】开始导入地址信息，开始预处理",DateFormatUtils.format(new Date(),"HH:mm:ss.SSS")));
        MessageVO messageVO;
        try {
            projectId = httpServletRequest.getAttribute("projectId") == null ? null : httpServletRequest.getAttribute("projectId").toString();
            //项目编号不能为空
            if (StringUtils.isBlank(projectId)) {
                return new MessageVO(PropertyErrorCodeEnum.PUB_PROJECT_ID_EMPTY_ERR.getErrorCode());
            }

            //判断参数合法性
            boolean isMultipart = ServletFileUpload.isMultipartContent(httpServletRequest);
            if (!isMultipart) {
                //是否是带文件上传的表单
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_IMPORT_FILE_LOST_ERR.getErrorCode());
            }
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) httpServletRequest;
            Map<String, MultipartFile> fileList = multipartRequest.getFileMap();
            if (fileList.size() < 1) {
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_IMPORT_FILE_LOST_ERR.getErrorCode());
            }
            if (fileList.size() > 1) {
                //目前仅支持一次处理单个文件
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_EXCEL_FILE_TOO_MANY_ERR.getErrorCode());
            }
            List<Sheet> availableSheets = new ArrayList<>(); //合法的Sheet页
            //获取Excel文件
            Map.Entry<String, MultipartFile> fileEntry = fileList.entrySet().iterator().next();
            MultipartFile excelFile = fileEntry.getValue();
            String excelFileName = excelFile.getOriginalFilename();
            // 获取上传文件的类型
            String excelContentType = StringHandlerUtil.copySubStr(excelFileName, excelFileName.lastIndexOf('.'), excelFileName.length());
            if (!(".xls".equalsIgnoreCase(excelContentType) || ".xlsx".equalsIgnoreCase(excelContentType))) {
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_IMPORT_FILE_TYPE_ERR.getErrorCode());
            }
            List<PropertyProjectAddressRowDTO> errorImportDataList;
            PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO;
            //创建Excel操作对象，07之前版本(*.xls)使用HSSFWorkBook 07之后版本使用（*.xlsx）XSSFWorkbook
            try (Workbook workbook = ExportUtil.getWorkbook(excelFile.getInputStream(), excelFileName)) {

                //对导入文件的数据格式等基本信息进行合法性初步检测
                messageVO = checkImportFileValid(workbook, availableSheets);
                if (!messageVO.getMsgCode().equals(BaseErrorCodeEnum.SUCCESS.getErrorCode().getMainCode())) {
                    return messageVO;
                }
                //处理Excel文件中的地址数据
                propertyProjectSaveImportAddressDTO = new PropertyProjectSaveImportAddressDTO();
                errorImportDataList = getImportAddressFromFile(projectId, propertyProjectSaveImportAddressDTO, availableSheets);
            }

            //若有非法数据，返回非法数据
            if (!errorImportDataList.isEmpty()) {
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_IMPORT_FILE_INFO_INVALID_ERR.getErrorCode(), errorImportDataList);
            }
            //System.out.println(String.format("【%s】导入的地址信息预处理成功，开始保存",DateFormatUtils.format(new Date(),"HH:mm:ss.SSS")));

            //将已整理好的地址数据插入数据库
            iPropertyAddressInfoServiceClient.saveImportAddressInfo(propertyProjectSaveImportAddressDTO);


            //System.out.println(String.format("【%s】导入的地址信息预保存成功",DateFormatUtils.format(new Date(),"HH:mm:ss.SSS")));
            messageVO = new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode());
            //底层使用子线程进行了异步提交，等待1秒再返回前端，一定程度上缓解前端导入成功后马上查询时尚无数据的情况
            Thread.sleep(1000);
        } catch (Exception e) {
            throw new DataAccessException("【物业_项目_导入地址信息】导入地址信息失败", e);
        }
        return messageVO;
    }


    /**
     * <desc>
     *      对导入文件的文件格式等基本信息进行合法性初步检测.
     * </desc>
     *
     * @param workbook        Excel操作对象
     * @param availableSheets 合法可用到Sheet页
     * @return MessageVO 标准格式化响应结果
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private MessageVO checkImportFileValid(Workbook workbook, List<Sheet> availableSheets) {

        //获取Excel的Sheet页面数，每个Excel文件至少会有一个Sheet页(Excel文件本身到限定)
        int sheetCount = workbook.getNumberOfSheets();
        int totalRowsCount = 0;
        //遍历当前文件的所有Sheet页，进行合法性检测
        for (int sheetIndex = 0; sheetIndex < sheetCount; sheetIndex++) {
            int rowsCountOfCurrentSheet = workbook.getSheetAt(sheetIndex).getPhysicalNumberOfRows();
            totalRowsCount += rowsCountOfCurrentSheet;
            //导入的地址数量超出限制,提前退出（sheetCount = 1 * sheetCount 代表标题行的数量）
            if (totalRowsCount > PlatformConstants.MAX_IMPORT_ADDRESS_COUNT + sheetCount) {
                ErrorCode errorCode = PropertyErrorCodeEnum.PROJECT_IMPORT_ROWS_TOO_MANY_ERR.getErrorCode();
                return new MessageVO(errorCode,
                        String.format(errorCode.getCodeMsg(), PlatformConstants.MAX_IMPORT_ADDRESS_COUNT));
            }
            if (rowsCountOfCurrentSheet < 1) {
                continue;
            }

            //对当前Sheet的列数量进行合法性判断
            int columnCount = workbook.getSheetAt(sheetIndex).getRow(0).getPhysicalNumberOfCells();
            if (columnCount != PlatformConstants.ADRESS_EXCEL_COLUMN_TITLES.length) {
                return new MessageVO(PropertyErrorCodeEnum.PROJECT_EXCEL_COLUMN_COUNT_MISMATCH_ERR.getErrorCode());
            }

            //每个Sheet页的第一页为列标题，进行标题头名称进行合法性判断
            DataFormatter dataFormatter = new DataFormatter();
            for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
                String oneFieldValue = dataFormatter.formatCellValue(workbook.getSheetAt(sheetIndex).getRow(0).getCell(columnIndex));

                String columnTitle = PlatformConstants.ADRESS_EXCEL_COLUMN_TITLES[columnIndex];
                if (!StringHandlerUtil.compareStrWithOutEmpty(oneFieldValue, columnTitle)) {
                    ErrorCode errorCode = PropertyErrorCodeEnum.PROJECT_EXCEL_COLUMN_TITLE_MISMATCH_ERR.getErrorCode();
                    return new MessageVO(errorCode,
                            String.format(errorCode.getCodeMsg(), oneFieldValue, columnTitle));
                }
            }

            //至少有一行实际数据可导入才加入Sheet处理列表
            if (rowsCountOfCurrentSheet > 1) {
                availableSheets.add(workbook.getSheetAt(sheetIndex));
            }

        }//end Sheet遍历

        //没有数据
        if (availableSheets.isEmpty()) {
            return new MessageVO(PropertyErrorCodeEnum.PROJECT_IMPORT_FILE_NO_DATA_ERR.getErrorCode());
        }
        return new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode());
    }


    /**
     * <desc>
     *      从可用的Sheet页中解析地址信息（含楼栋、单元、房屋），
     * </desc>
     *
     * @param propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @param availableSheets                     合法可用到Sheet页
     * @return 错误的地址信息及其错误原因
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private List<PropertyProjectAddressRowDTO> getImportAddressFromFile(
            String projectId,
            PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO,
            List<Sheet> availableSheets
    ) throws Exception {

        //初始化导入地址的信息存储对象（初始化项目编号、数据库中的所有楼栋和单元信息）
        propertyProjectSaveImportAddressDTO.setProjectId(projectId);
        propertyProjectSaveImportAddressDTO.setBuildInfoVOSInDB(getBuildInfoFromDB(projectId));
        propertyProjectSaveImportAddressDTO.setUnitInfoVOSInDB(getUnitInfoFromDB(projectId));
        //当前项目房间总数低于指定数量时，直接一次性获取所有房间到内存，否则后续逐楼栋获取
        if (getRoomCountInDB(propertyProjectSaveImportAddressDTO.getUnitInfoVOSInDB()) < 10000){
            propertyProjectSaveImportAddressDTO.setRoomInfoVOSInDB(getRoomInfoFromDB(projectId));
        } else
        {
            propertyProjectSaveImportAddressDTO.setRoomInfoVOSInDB(null);
        }

        //Excel单元格数据操作对象
        DataFormatter dataFormatter = new DataFormatter();
        //错误的行信息列表
        List<PropertyProjectAddressRowDTO> errorImportDataList = new ArrayList<>();


        //遍历所有可用Sheet，逐行处理每个Sheet的数据
        for (Sheet oneSheet : availableSheets) {
            int rowsCountOfCurrentSheet = oneSheet.getPhysicalNumberOfRows();
            for (int rowIndex = 1; rowIndex < rowsCountOfCurrentSheet; rowIndex++) {
                //对当前Sheet中的当前行进行数据处理
                PropertyProjectAddressRowDTO addressInfo = handleOneRowAddressInfo(oneSheet.getRow(rowIndex),
                        propertyProjectSaveImportAddressDTO, dataFormatter);
                if (StringUtils.isBlank(addressInfo.getBuildName())){  //楼栋名称为空的跳过处理
                    continue;
                }
                //若存在错误信息，则将加入错误列表
                if (!addressInfo.getErrorCodes().isEmpty()) {
                    this.addErrorAddressInfoToList(errorImportDataList,addressInfo);
                }
            }
        }



        //二次处理,主要是逐楼栋批量查询房屋信息，然后逐楼栋逐单元对房屋信息进行进一步检测并完善
        handleAllRowsRoomInfo(propertyProjectSaveImportAddressDTO, errorImportDataList);

        return errorImportDataList;
    }


    /**
     * <desc>
     *      对房屋信息进行额外处理
     * </desc>
     *
     * @param propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @author LewisLouis
     * @createDate 2017-10-23
     */
    private void handleAllRowsRoomInfo(PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO,
                                       List<PropertyProjectAddressRowDTO> errorImportDataList) throws Exception {
        String projectId = propertyProjectSaveImportAddressDTO.getProjectId(); //取出项目编号
        //取出导入的楼栋信息列表
        Map<String, PropertyProjectImportBuildInfoDTO> buildInfosInFile = propertyProjectSaveImportAddressDTO.getAddressInfosInFile();
        //数据库中的当前项目所有楼栋信息。
        List<PropertyProjectBuildInfoVO> buildInfosInDB = propertyProjectSaveImportAddressDTO.getBuildInfoVOSInDB();

        //遍历楼栋，逐楼栋处理楼栋下的房屋信息
        Map<String, PropertyProjectImportBuildInfoDTO> buildInfoPOSInFile = propertyProjectSaveImportAddressDTO.getAddressInfosInFile();
        for (Map.Entry<String, PropertyProjectImportBuildInfoDTO> oneBuildEntry : buildInfoPOSInFile.entrySet()) {
            PropertyProjectImportBuildInfoDTO oneBuildInFile = oneBuildEntry.getValue();
            String buildName = oneBuildEntry.getKey();
            String buildId = getBuildIdByBuildName(buildName, buildInfosInFile, buildInfosInDB);
            if (StringUtils.isBlank(buildId)) {
                throw new DataAccessException(String.format("BuildName: %s not exists in project:%s", oneBuildInFile.getBuildName(), projectId));
            }

            //查询当前楼栋下所有房屋信息
            List<PropertyProjectRoomInfoVO> roomInfosInOneBuildInDB;

            if (!checkBuildIdInDB(propertyProjectSaveImportAddressDTO,buildId))
            {
                //当前楼栋不存在时，无需获取房屋信息
                roomInfosInOneBuildInDB = new ArrayList<>();
            } else
            {
                if (null != propertyProjectSaveImportAddressDTO.getRoomInfoVOSInDB()){
                    //当前楼栋存在时，若当前项目房间总数低于指定数量时，所有房间已被一次性获取到内存，直接从内存取
                    roomInfosInOneBuildInDB = getRoomInfoInDBByBuildId(propertyProjectSaveImportAddressDTO.getRoomInfoVOSInDB(),buildId);
                } else
                {
                    //当前楼栋存在时，若当前项目房间总数大于指定数量时，需要逐楼栋从数据库取房间
                    PropertyProjectGetRoomInfoDTO propertyProjectGetRoomInfoDTO = new PropertyProjectGetRoomInfoDTO();
                    propertyProjectGetRoomInfoDTO.setProjectId(projectId);
                    propertyProjectGetRoomInfoDTO.setCurrentPage("1");
                    propertyProjectGetRoomInfoDTO.setPageSize(String.valueOf(PlatformConstants.MAX_ROOM_NUM));
                    propertyProjectGetRoomInfoDTO.setBuildId(buildId);
                    Page<PropertyProjectRoomInfoVO> propertyProjectRoomInfoVOPage
                            = iPropertyRoomInfoServiceClient.getPage(propertyProjectGetRoomInfoDTO);
                    roomInfosInOneBuildInDB = propertyProjectRoomInfoVOPage.getRows();
                }

            }



            //遍历当前楼栋下的单元
            Map<String, PropertyProjectImportUnitInfoDTO> unitInfoPOSInOneBuildInFile = oneBuildInFile.getUnitsInFile();
            for (Map.Entry<String, PropertyProjectImportUnitInfoDTO> oneUnitEntry : unitInfoPOSInOneBuildInFile.entrySet()) {
                PropertyProjectImportUnitInfoDTO oneUnitInFile = oneUnitEntry.getValue();
                List<PropertyProjectRoomInfoVO> roomInfosInOneUnitInDB = getRoomsInOneUnitInDB(roomInfosInOneBuildInDB,oneUnitInFile.getUnitName());
                //遍历当前单元下的房间
                Map<String, PropertyProjectImportRoomInfoDTO> roomInfoPOSInOneUnitInFile = oneUnitInFile.getRoomsInFile();
                for (Map.Entry<String, PropertyProjectImportRoomInfoDTO> oneRoomEntry : roomInfoPOSInOneUnitInFile.entrySet()){
                    PropertyProjectImportRoomInfoDTO oneRoomInFile = oneRoomEntry.getValue();

                    PropertyProjectRoomInfoVO oneRoomInDB = getRoomInfoFromBuildInDBByRoomNum(
                            oneUnitInFile.getUnitName(), oneRoomInFile.getRoomNum(), roomInfosInOneBuildInDB);
                    if (StringUtils.isNotBlank(oneRoomInFile.getRoomAlias())){
                        if (checkRoomAliasExists(oneRoomInFile.getRoomNum(), oneRoomInFile.getRoomAlias(),
                                roomInfosInOneUnitInDB, roomInfoPOSInOneUnitInFile)) {
                            //访客呼叫码已被当前单元下的其它房屋占用
                            oneRoomInFile.getPropertyProjectAdressRowDTO().getErrorCodes().add(PropertyErrorCodeEnum.PROJECT_ROOM_ALIAS_REPEAT_ERR.getErrorCode());
                            this.addErrorAddressInfoToList(errorImportDataList,oneRoomInFile.getPropertyProjectAdressRowDTO());
                        }
                    } else {
                        if ((null != oneRoomInDB) && (StringUtils.isNotBlank(oneRoomInDB.getRoomAlias()))){
                            //当导入的房屋没有访客呼叫码时，若数据库中已存在本房间且访客呼叫码不为空，则直接取库中的访客呼叫码
                            oneRoomInFile.setRoomAlias(oneRoomInDB.getRoomAlias());
                        } else{
                            String newRoomAlias = getMinAvaliableRoomAlias(oneRoomInFile.getRoomNum(),roomInfosInOneUnitInDB,roomInfoPOSInOneUnitInFile);
                            if (StringHandlerUtil.strToIntDef(newRoomAlias,0) > PlatformConstants.MAX_ROOM_NUM) {
                                oneRoomInFile.getPropertyProjectAdressRowDTO().getErrorCodes().add(PropertyErrorCodeEnum.PROJECT_IMPORT_TOO_MANY_ROOM_ERR.getErrorCode());
                                this.addErrorAddressInfoToList(errorImportDataList,oneRoomInFile.getPropertyProjectAdressRowDTO());
                            }
                            oneRoomInFile.setRoomAlias(newRoomAlias);
                        }

                    }

                    oneRoomInFile.setImportAddressOperationType(ImportAddressOperationType.NONE);
                    oneRoomInFile.setNeedNotifyIntercom(false);
                    if (oneRoomInDB == null) {
                        //添加
                        oneRoomInFile.setImportAddressOperationType(ImportAddressOperationType.ADD);
                        oneRoomInFile.setNeedNotifyIntercom(true);
                        String roomId = LogicIdUtil.bussinessId();
                        oneRoomInFile.setRoomId(roomId);
                    } else {
                        //修改
                        if ((oneRoomInDB.getLiftDoorType() != oneRoomInFile.getLiftDoorType())
                                ||(!StringHandlerUtil.compareStrWithOutEmpty(oneRoomInDB.getRoomAlias(),oneRoomInFile.getRoomAlias()))
                                ||(!StringHandlerUtil.compareStrIgnoreCaseWithOutEmpty(oneRoomInDB.getRemark(),oneRoomInFile.getRemark()))
                                ||(!StringHandlerUtil.compareStrWithOutEmpty(oneRoomInDB.getBuiltArea(),oneRoomInFile.getBuildId()))){
                            oneRoomInFile.setImportAddressOperationType(ImportAddressOperationType.UPDATE);
                        }
                        if ((oneRoomInDB.getLiftDoorType() != oneRoomInFile.getLiftDoorType())
                                ||(!StringHandlerUtil.compareStrWithOutEmpty(oneRoomInDB.getRoomAlias(),oneRoomInFile.getRoomAlias()))
                                ||(!StringHandlerUtil.compareStrIgnoreCaseWithOutEmpty(oneRoomInDB.getRemark(),oneRoomInFile.getRemark()))
                                ||(!StringHandlerUtil.compareStrWithOutEmpty(oneRoomInDB.getBuiltArea(),oneRoomInFile.getBuildId()))){
                            oneRoomInFile.setImportAddressOperationType(ImportAddressOperationType.UPDATE);
                        }

                        if ((oneRoomInDB.getLiftDoorType() != oneRoomInFile.getLiftDoorType())
                                ||(!StringHandlerUtil.compareStrWithOutEmpty(oneRoomInDB.getRoomAlias(),oneRoomInFile.getRoomAlias()))){
                            oneRoomInFile.setNeedNotifyIntercom(true);
                        }
                        oneRoomInFile.setRoomId(oneRoomInDB.getRoomId());
                    }
                }
            }
        }
    }


    /**
     * <desc>
     *      根据Excel的一行数据获取单条"楼栋-单元-房屋信息及其错误码列表".
     * </desc>
     *
     * @param hssfRow                             Excel的一行数据
     * @param propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @param dataFormatter                       Excel单元格数据的读取器
     * @return 楼栋-单元-房屋信息及其错误码列表
     * @author LewisLouis
     * @createDate 2017-10-12
     */
    private PropertyProjectAddressRowDTO handleOneRowAddressInfo(
            Row hssfRow,
            PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO,
            DataFormatter dataFormatter) {

        //将Excel中的当前行数据转换为对应的内存对象，并对文件中的数据基本格式进行检测
        PropertyProjectAddressRowDTO excelRowAddressInfo = excelRowToAddressInfo(hssfRow, dataFormatter);
        //本行数据的错误列表
        List<ErrorCode> errorCodes = excelRowAddressInfo.getErrorCodes();

        if (StringUtils.isEmpty(excelRowAddressInfo.getBuildName())) {
            return excelRowAddressInfo;
        }

        //处理本行导入数据库中的楼栋信息
        PropertyProjectImportBuildInfoDTO propertyProjectImportBuildInfoDTO = handleOneRowBuildInfo(
                propertyProjectSaveImportAddressDTO, excelRowAddressInfo, errorCodes);


        if (StringUtils.isEmpty(excelRowAddressInfo.getUnitName())) {
            return excelRowAddressInfo;
        }

        //处理本行导入数据库中的单元信息
        PropertyProjectImportUnitInfoDTO propertyProjectImportUnitInfoDTO = handleOneRowUnitInfo(
                propertyProjectSaveImportAddressDTO, excelRowAddressInfo, propertyProjectImportBuildInfoDTO, errorCodes);

        //处理本行导入数据库中的房屋信息
        handleOneRowRoomInfo(
                propertyProjectSaveImportAddressDTO, excelRowAddressInfo, propertyProjectImportUnitInfoDTO, errorCodes);

        return excelRowAddressInfo;
    }


    /**
     * <desc>
     *      处理单行导入数据中的楼栋信息.
     * </desc>
     *
     * @param propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @author LewisLouis
     * @createDate 2017-10-23
     */
    private PropertyProjectImportBuildInfoDTO handleOneRowBuildInfo(PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO,
                                                                    PropertyProjectAddressRowDTO excelRowAddressInfo, List<ErrorCode> errorCodes) {
        //Excel中所有楼栋信息的存储列表
        // Map<String, PropertyProjectImportBuildInfoDTO> buildInfoPOSInFile = propertyProjectSaveImportAddressDTO.getBuildInfoPOSInFile();
        Map<String, PropertyProjectImportBuildInfoDTO> buildInfoPOSInFile = propertyProjectSaveImportAddressDTO.getAddressInfosInFile();

        //项目ID
        String projectId = propertyProjectSaveImportAddressDTO.getProjectId();

        //当前行所属的楼栋名称
        String buildName = excelRowAddressInfo.getBuildName();

        //根据房间号解析出楼层号
        int groundFloorNum = getFloorNoByRoomNum(excelRowAddressInfo.getRoomNum());

        //处理楼栋相关信息（可能新增楼栋，或更新楼栋的地面楼层或或总楼层数）
        PropertyProjectImportBuildInfoDTO propertyProjectImportBuildInfoDTO;
        if (!buildInfoPOSInFile.containsKey(buildName)) {
            //若楼栋列表中还未加入此楼栋，则初始化楼栋对象
            propertyProjectImportBuildInfoDTO = new PropertyProjectImportBuildInfoDTO();
            //根据楼栋名称尝试从数据库中的楼栋信息列表中获取楼栋信息.
            PropertyProjectBuildInfoVO propertyProjectBuildInfoVOInDB = getBuildDBInfoByName(buildName,
                    propertyProjectSaveImportAddressDTO.getBuildInfoVOSInDB());
            String buildNum = excelRowAddressInfo.getBuildNum();
            propertyProjectImportBuildInfoDTO.setImportAddressOperationType(ImportAddressOperationType.NONE);
            if (null == propertyProjectBuildInfoVOInDB) {
                //如果在数据库中没有该楼栋信息，则需要创建一个楼栋，需要确定楼栋相关信息

                //生成楼栋Id
                String buildId = LogicIdUtil.bussinessId();
                propertyProjectImportBuildInfoDTO.setBuildId(buildId);

                //添加操作
                propertyProjectImportBuildInfoDTO.setImportAddressOperationType(ImportAddressOperationType.ADD);

                //楼栋名称取文件中的楼栋名称
                propertyProjectImportBuildInfoDTO.setBuildName(excelRowAddressInfo.getBuildName());

                //项目编号
                propertyProjectImportBuildInfoDTO.setProjectId(projectId);

                if (StringUtils.isBlank(buildNum)) {
                    //导入文件中该行楼栋编号为空，应取在数据中和已处理的文件中的楼栋列表的最小值
                    int intBuildNum = getMinAvailableBuildNum(buildInfoPOSInFile, propertyProjectSaveImportAddressDTO.getBuildInfoVOSInDB());
                    if (intBuildNum > PlatformConstants.MAX_BUILD_NUM) { //若取出的楼栋编号越界，则登记错误信息
                        errorCodes.add(PropertyErrorCodeEnum.PROJECT_IMPORT_TOO_MANY_BUILD_ERR.getErrorCode());
                    }
                    buildNum = StringHandlerUtil.autlSupply(3, String.valueOf(intBuildNum), "0");
                    propertyProjectImportBuildInfoDTO.setBuildNum(buildNum);
                } else { // 楼栋编号不为空，则进行校验
                    PropertyProjectGetBuildInfoDTO propertyProjectGetBuildInfoDTO = new PropertyProjectGetBuildInfoDTO();
                    propertyProjectGetBuildInfoDTO.setProjectId(projectId);
                    propertyProjectGetBuildInfoDTO.setBuildNum(buildNum);
                    PropertyProjectBuildInfoVO oneBuildInfo = iPropertyBuildInfoServiceClient.getOneBuildInfo(propertyProjectGetBuildInfoDTO);
                    if (oneBuildInfo != null){
                        errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NUM_EXIST_ERR.getErrorCode());
                    } else if (!NumberHandlerUtil.isInRange(StringHandlerUtil.strToIntDef(buildNum,0),PlatformConstants.MIN_BUILD_NUM,PlatformConstants.MAX_BUILD_NUM)) {
                        errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NUM_INVALID_ERR.getErrorCode());
                    } else {
                        propertyProjectImportBuildInfoDTO.setBuildNum(buildNum);
                    }
                }

                //地下楼层(默认为0)
                propertyProjectImportBuildInfoDTO.setUndergroundFloorNum(0);
                //地面楼层（从房间号解析）
                if (groundFloorNum <= PlatformConstants.MAX_FLOOR_NUM) {
                    propertyProjectImportBuildInfoDTO.setGroundFloorNum(groundFloorNum);
                    //总楼层（取地下楼层和地面楼层之和）
                    propertyProjectImportBuildInfoDTO.setFloorNum(groundFloorNum);
                } else {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_FLOOR_NUM_ERR.getErrorCode());
                }

                //其它属性，如status、createTime、updateTime等由project-service确定
            } else {
                //如果数据库中已有该楼栋信息，则仅需要保证地面楼层或或总楼层数变化时更新楼栋信息
                //修改操作
                //将数据库中的查询出的部分关键相关信息取出
                propertyProjectImportBuildInfoDTO.setBuildNum(propertyProjectBuildInfoVOInDB.getBuildNum());
                propertyProjectImportBuildInfoDTO.setBuildId(propertyProjectBuildInfoVOInDB.getBuildId());
                //地下楼层直接取数据中的
                propertyProjectImportBuildInfoDTO.setUndergroundFloorNum(propertyProjectBuildInfoVOInDB.getUndergroundFloorNum());
                //地面楼层 取数据库和当前房间号解析出的楼层的较大者
                groundFloorNum = groundFloorNum > propertyProjectBuildInfoVOInDB.getGroundFloorNum() ?
                        groundFloorNum : propertyProjectBuildInfoVOInDB.getGroundFloorNum();
                propertyProjectImportBuildInfoDTO.setGroundFloorNum(groundFloorNum);
                if (groundFloorNum + propertyProjectBuildInfoVOInDB.getUndergroundFloorNum() <= PlatformConstants.MAX_FLOOR_NUM) {
                    //总楼层（取地下楼层和地面楼层之和）
                    propertyProjectImportBuildInfoDTO.setFloorNum(groundFloorNum + propertyProjectBuildInfoVOInDB.getUndergroundFloorNum());
                } else {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_FLOOR_NUM_ERR.getErrorCode());
                }
                if (StringUtils.isNotBlank(buildNum)) {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_ADDRESS_BUILD_NUM_IMPORT_ERR.getErrorCode());
                }
                if ((propertyProjectImportBuildInfoDTO.getGroundFloorNum() != propertyProjectBuildInfoVOInDB.getGroundFloorNum())
                        ||(propertyProjectImportBuildInfoDTO.getUndergroundFloorNum() != propertyProjectBuildInfoVOInDB.getUndergroundFloorNum())
                        ||(propertyProjectImportBuildInfoDTO.getFloorNum() != propertyProjectBuildInfoVOInDB.getFloorNum())){
                    if (StringUtils.isBlank(buildNum)) {
                        propertyProjectImportBuildInfoDTO.setImportAddressOperationType(ImportAddressOperationType.UPDATE);
                    } else {
                        errorCodes.add(PropertyErrorCodeEnum.PROJECT_ADDRESS_BUILD_NUM_IMPORT_ERR.getErrorCode());
                    }
                }

            }
            propertyProjectImportBuildInfoDTO.setBuildName(buildName);
            buildInfoPOSInFile.put(buildName, propertyProjectImportBuildInfoDTO); //将新增的楼栋对象加入到列表中

        } else {  //当前行的楼栋信息已登记，则仅根据当前行的房间信息更新楼栋的地面楼层或或总楼层数即可）
            propertyProjectImportBuildInfoDTO = buildInfoPOSInFile.get(buildName);

            // 若楼栋编号存在，则将此条数据楼栋编号校验一遍，以便返回精确的错误信息
            String buildNum = excelRowAddressInfo.getBuildNum();
            if (StringUtils.isNotBlank(buildNum)) {
                PropertyProjectGetBuildInfoDTO propertyProjectGetBuildInfoDTO = new PropertyProjectGetBuildInfoDTO();
                propertyProjectGetBuildInfoDTO.setProjectId(projectId);
                propertyProjectGetBuildInfoDTO.setBuildNum(buildNum);
                PropertyProjectBuildInfoVO oneBuildInfo = iPropertyBuildInfoServiceClient.getOneBuildInfo(propertyProjectGetBuildInfoDTO);
                if (oneBuildInfo != null && oneBuildInfo.getBuildName().equals(buildName)){
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_ADDRESS_BUILD_NUM_IMPORT_ERR.getErrorCode());
                } else if (oneBuildInfo != null && !oneBuildInfo.getBuildName().equals(buildName)){
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NUM_EXIST_ERR.getErrorCode());
                }
                if (!NumberHandlerUtil.isInRange(StringHandlerUtil.strToIntDef(buildNum,0),PlatformConstants.MIN_BUILD_NUM,PlatformConstants.MAX_BUILD_NUM)) {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NUM_INVALID_ERR.getErrorCode());
                }
            }

            //地下楼层直接取数据中的
            //地面楼层 取数据库和当前房间号解析出的楼层的较大者
            groundFloorNum = groundFloorNum > propertyProjectImportBuildInfoDTO.getGroundFloorNum() ?
                    groundFloorNum : propertyProjectImportBuildInfoDTO.getGroundFloorNum();
            propertyProjectImportBuildInfoDTO.setGroundFloorNum(groundFloorNum);
            if (groundFloorNum + propertyProjectImportBuildInfoDTO.getUndergroundFloorNum() <= PlatformConstants.MAX_FLOOR_NUM) {
                //总楼层（取地下楼层和地面楼层之和）
                propertyProjectImportBuildInfoDTO.setFloorNum(groundFloorNum + propertyProjectImportBuildInfoDTO.getUndergroundFloorNum());
            } else {
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_FLOOR_NUM_ERR.getErrorCode());
            }
            if (propertyProjectImportBuildInfoDTO.getImportAddressOperationType().getType() == ImportAddressOperationType.NONE.getType()) {
                propertyProjectImportBuildInfoDTO.setImportAddressOperationType(ImportAddressOperationType.UPDATE);
            }
        }
        return propertyProjectImportBuildInfoDTO;
    }

    /**
     * <desc>
     *      处理单行导入数据中的单元信息.
     * </desc>
     *
     * @param propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @author LewisLouis
     * @createDate 2017-10-23
     */
    private PropertyProjectImportUnitInfoDTO handleOneRowUnitInfo(PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO,
                                                                  PropertyProjectAddressRowDTO excelRowAddressInfo,
                                                                  PropertyProjectImportBuildInfoDTO propertyProjectImportBuildInfoDTO,
                                                                  List<ErrorCode> errorCodes) {
        //处理单元相关信息（仅可能新增单元 或更新单元代号）
        PropertyProjectImportUnitInfoDTO importUnitInfoInFileDTO;

        //Excel中所有单元信息的存储列表
//        Map<String, Map<String, PropertyProjectImportUnitInfoDTO>> unitInfoPOSInFile = propertyProjectSaveImportAddressDTO.getUnitInfoPOSInFile();


        //项目ID
        String projectId = propertyProjectSaveImportAddressDTO.getProjectId();

        //当前行所属的楼栋名称
        String buildName = excelRowAddressInfo.getBuildName();

        //当前行所属的单元名称
        String unitName = excelRowAddressInfo.getUnitName();

        //取出当前楼栋的单元列表，若没有则创建该列表
        //Excel中所有楼栋信息的存储列表
        Map<String, PropertyProjectImportBuildInfoDTO> buildInfoPOSInFile = propertyProjectSaveImportAddressDTO.getAddressInfosInFile();
        PropertyProjectImportBuildInfoDTO oneBuildInFile = buildInfoPOSInFile.get(buildName);
        if (null == oneBuildInFile)
        {
            throw new DataAccessException(String.format("Can not find: %s not exists in project:%s", buildName, projectId));
        }
        Map<String, PropertyProjectImportUnitInfoDTO> unitsOfOneBuildInFile = oneBuildInFile.getUnitsInFile();

        //判断单元代号存在性
        if (StringUtils.isNotBlank(excelRowAddressInfo.getUnitAlias())){
            if (checkUnitAliasExists(buildName,excelRowAddressInfo.getUnitAlias(), excelRowAddressInfo.getUnitName(), propertyProjectSaveImportAddressDTO)) {
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_ALIAS_REPEAT_ERR.getErrorCode());
            }
        }


        if (!unitsOfOneBuildInFile.containsKey(unitName)) {
            //若当前楼栋的单元列表中还未加入此单元，则初始化单元对象
            importUnitInfoInFileDTO = new PropertyProjectImportUnitInfoDTO();
            //根据楼栋名称和单元名称尝试从数据库中的楼栋信息列表中获取楼栋信息.
            PropertyProjectUnitInfoVO oldUnitInfoVOInDB = getUnitDBInfoByName(buildName, unitName,
                    propertyProjectSaveImportAddressDTO.getUnitInfoVOSInDB());

            String unitNum = excelRowAddressInfo.getUnitNum();
            importUnitInfoInFileDTO.setImportAddressOperationType(ImportAddressOperationType.NONE);
            importUnitInfoInFileDTO.setNeedNotifyIntercom(false);
            if (null == oldUnitInfoVOInDB) {
                //如果在数据库中没有该单元信息，则需要创建一个单元，需要确定单元相关信息
                //生成单元Id
                String unitId = LogicIdUtil.bussinessId();
                importUnitInfoInFileDTO.setUnitId(unitId);
                importUnitInfoInFileDTO.setBuildId(propertyProjectImportBuildInfoDTO.getBuildId());
                //添加
                importUnitInfoInFileDTO.setImportAddressOperationType(ImportAddressOperationType.ADD);
                //单元名称取文件中的单元名称
                importUnitInfoInFileDTO.setUnitName(excelRowAddressInfo.getUnitName());
                //项目编号
                importUnitInfoInFileDTO.setProjectId(projectId);
                //单元编号
                if (StringUtils.isBlank(unitNum)) {
                    int intUnitNum = getMinAvailableUnitNum(unitsOfOneBuildInFile, buildName, propertyProjectSaveImportAddressDTO.getUnitInfoVOSInDB());
                    if (intUnitNum > PlatformConstants.MAX_UNIT_NUM) {
                        errorCodes.add(PropertyErrorCodeEnum.PROJECT_IMPORT_TOO_MANY_UNIT_ERR.getErrorCode());
                    }
                    unitNum = StringHandlerUtil.autlSupply(2, String.valueOf(intUnitNum), "0");
                    importUnitInfoInFileDTO.setUnitNum(unitNum);
                } else { // 单元编号不为空，则进行校验
                    PropertyProjectGetUnitInfoDTO propertyProjectGetUnitInfoDTO = new PropertyProjectGetUnitInfoDTO();
                    propertyProjectGetUnitInfoDTO.setBuildId(propertyProjectImportBuildInfoDTO.getBuildId());
                    propertyProjectGetUnitInfoDTO.setUnitNum(unitNum);
                    PropertyProjectUnitInfoVO oneUnitInfo = iPropertyUnitInfoServiceClient.getOneUnitInfo(propertyProjectGetUnitInfoDTO);
                    if (oneUnitInfo != null){
                        errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NUM_EXIST_ERR.getErrorCode());
                    } else if (!NumberHandlerUtil.isInRange(StringHandlerUtil.strToIntDef(unitNum,0),PlatformConstants.MIN_UNIT_NUM,PlatformConstants.MAX_UNIT_NUM)) {
                        errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NUM_INVALID_ERR.getErrorCode());
                    } else {
                        importUnitInfoInFileDTO.setUnitNum(unitNum);
                    }
                }

                if (StringUtils.isBlank(excelRowAddressInfo.getUnitAlias())){
                    String newUnitAlias = getMinAvaliableUnitAlias(propertyProjectSaveImportAddressDTO,
                            buildName,unitName,oneBuildInFile.getBuildNum(),unitNum);
                    importUnitInfoInFileDTO.setUnitAlias(newUnitAlias);
                } else {
                    importUnitInfoInFileDTO.setUnitAlias(excelRowAddressInfo.getUnitAlias());
                }

                //其它属性，如status、createTime、updateTime由project-service确定
            } else {
                //如果数据库中已有该单元信息，则仅需要保证单元代号变化时更新单元信息
                //将数据库中的查询出的部分关键相关信息取出
                //添加
                importUnitInfoInFileDTO.setUnitNum(oldUnitInfoVOInDB.getUnitNum());
                importUnitInfoInFileDTO.setUnitName(unitName);
                importUnitInfoInFileDTO.setBuildId(oldUnitInfoVOInDB.getBuildId());
                importUnitInfoInFileDTO.setUnitId(oldUnitInfoVOInDB.getUnitId());
                if (StringUtils.isNotBlank(unitNum)) {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_ADDRESS_UNIT_NUM_IMPORT_ERR.getErrorCode());
                }
                if (StringUtils.isBlank(excelRowAddressInfo.getUnitAlias())){
                    //若数据库中该单元已存在单元代号，本次导入资料中未导入，则直接使用库中的单元代号
                    importUnitInfoInFileDTO.setUnitAlias(oldUnitInfoVOInDB.getUnitAlias());
                } else{
                    importUnitInfoInFileDTO.setUnitAlias(excelRowAddressInfo.getUnitAlias());
                    if (!StringHandlerUtil.compareStrWithOutEmpty(oldUnitInfoVOInDB.getUnitAlias(),
                            importUnitInfoInFileDTO.getUnitAlias())){
                        if (StringUtils.isBlank(unitNum)) {
                            importUnitInfoInFileDTO.setNeedNotifyIntercom(true);
                            importUnitInfoInFileDTO.setImportAddressOperationType(ImportAddressOperationType.UPDATE);
                        } else {
                            errorCodes.add(PropertyErrorCodeEnum.PROJECT_ADDRESS_UNIT_ALIAS_IMPORT_ERR.getErrorCode());
                        }
                    };
                }


            }
            unitsOfOneBuildInFile.put(unitName, importUnitInfoInFileDTO); //将新增的单元对象加入到列表中
        } else {//当前行的单元信息已登记，则仅判断当前行的单元代号是否合法）
            // 同时验证单元编号是否合法
            String unitNum = excelRowAddressInfo.getUnitNum();
            if (StringUtils.isNotBlank(unitNum)) {
                PropertyProjectGetUnitInfoDTO propertyProjectGetUnitInfoDTO = new PropertyProjectGetUnitInfoDTO();
                propertyProjectGetUnitInfoDTO.setBuildId(propertyProjectImportBuildInfoDTO.getBuildId());
                propertyProjectGetUnitInfoDTO.setUnitNum(unitNum);
                PropertyProjectUnitInfoVO oneUnitInfo = iPropertyUnitInfoServiceClient.getOneUnitInfo(propertyProjectGetUnitInfoDTO);
                if (oneUnitInfo != null && !oneUnitInfo.getUnitName().equals(unitName)){
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NUM_EXIST_ERR.getErrorCode());
                } else if (oneUnitInfo != null && oneUnitInfo.getUnitName().equals(unitName)) {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_ADDRESS_UNIT_NAME_IMPORT_ERR.getErrorCode());
                }
                if (!NumberHandlerUtil.isInRange(StringHandlerUtil.strToIntDef(unitNum,0),PlatformConstants.MIN_UNIT_NUM,PlatformConstants.MAX_UNIT_NUM)) {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NUM_INVALID_ERR.getErrorCode());
                }
            }
            importUnitInfoInFileDTO = unitsOfOneBuildInFile.get(unitName);
            if (StringUtils.isNotBlank(excelRowAddressInfo.getUnitAlias())){
                if (!StringHandlerUtil.compareStrWithOutEmpty(importUnitInfoInFileDTO.getUnitAlias(), excelRowAddressInfo.getUnitAlias())) {
                    //相同单元名称对应不同的楼栋单元代号
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_ALIAS_MISMATCH_ERR.getErrorCode());
                }
            };
            if (importUnitInfoInFileDTO.getImportAddressOperationType().getType() == ImportAddressOperationType.NONE.getType()) {
                importUnitInfoInFileDTO.setImportAddressOperationType(ImportAddressOperationType.UPDATE);
            }
        }
        return importUnitInfoInFileDTO;
    }

    /**
     * <desc>
     *      处理单行导入数据中的房屋信息.
     * </desc>
     *
     * @param propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @author LewisLouis
     * @createDate 2017-10-23
     */
    private void handleOneRowRoomInfo(PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO,
                                      PropertyProjectAddressRowDTO excelRowAddressInfo,
                                      PropertyProjectImportUnitInfoDTO propertyProjectImportUnitInfoDTO,
                                      List<ErrorCode> errorCodes) {

        //项目ID
        String projectId = propertyProjectSaveImportAddressDTO.getProjectId();

        //当前行所属的楼栋名称
        String buildName = excelRowAddressInfo.getBuildName();

        //当前行所属的单元名称
        String unitName = excelRowAddressInfo.getUnitName();

        //处理房间相关信息（可能新增房间，或更新房间的访客呼叫码、电梯正背门、备注属性）
        PropertyProjectImportRoomInfoDTO propertyProjectImportRoomInfoDTO;
        //取出当前楼栋的当前单元的房屋列表，若没有则创建该列表

        Map<String, PropertyProjectImportRoomInfoDTO> roomsInOneUnitInFile = propertyProjectImportUnitInfoDTO.getRoomsInFile();

//        Map<String, Map<String, Map<String, PropertyProjectImportRoomInfoDTO>>> roomInfoPOSInFile
//                = propertyProjectSaveImportAddressDTO.getRoomInfoPOSInFile();
//        Map<String, Map<String, PropertyProjectImportRoomInfoDTO>> roomsInOneBuild;
//        if (roomInfoPOSInFile.containsKey(buildName)) {
//            roomsInOneBuild = roomInfoPOSInFile.get(buildName);
//        } else {
//            roomsInOneBuild = new HashMap<>();
//            roomInfoPOSInFile.put(buildName, roomsInOneBuild);
//        }
//        Map<String, PropertyProjectImportRoomInfoDTO> roomsInOneUnit;
//        if (roomsInOneBuild.containsKey(unitName)) {
//            roomsInOneUnit = roomsInOneBuild.get(unitName);
//        } else {
//            roomsInOneUnit = new HashMap<>();
//            roomsInOneBuild.put(unitName, roomsInOneUnit);
//        }

        if (!roomsInOneUnitInFile.containsKey(excelRowAddressInfo.getRoomNum())) {
            //若当前楼栋的当前单元的房屋列表中还未加入此房屋，则初始化房屋对象
            propertyProjectImportRoomInfoDTO = new PropertyProjectImportRoomInfoDTO();
            propertyProjectImportRoomInfoDTO.setRoomNum(excelRowAddressInfo.getRoomNum());
            propertyProjectImportRoomInfoDTO.setProjectId(projectId);
            propertyProjectImportRoomInfoDTO.setRoomAlias(excelRowAddressInfo.getRoomAlias());
            propertyProjectImportRoomInfoDTO.setLiftDoorType(excelRowAddressInfo.getLiftDoorType());
            propertyProjectImportRoomInfoDTO.setRemark(excelRowAddressInfo.getRemark());
            propertyProjectImportRoomInfoDTO.setBuildId(propertyProjectImportUnitInfoDTO.getBuildId());
            propertyProjectImportRoomInfoDTO.setUnitId(propertyProjectImportUnitInfoDTO.getUnitId());
            propertyProjectImportRoomInfoDTO.setPropertyProjectAdressRowDTO(excelRowAddressInfo);
            propertyProjectImportRoomInfoDTO.setBuiltArea(excelRowAddressInfo.getBuiltArea());
            roomsInOneUnitInFile.put(excelRowAddressInfo.getRoomNum(), propertyProjectImportRoomInfoDTO);
        } else {
            //若当前楼栋的当前单元的房屋列表中已加入此房屋，则判定为重复错误
            propertyProjectImportRoomInfoDTO = roomsInOneUnitInFile.get(excelRowAddressInfo.getRoomNum());
            if (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectImportRoomInfoDTO.getRoomNum(), excelRowAddressInfo.getRoomNum())) {
                //同一单元不允许存在两个相同的房间编号
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_ROOM_NUM_REPEAT_ERR.getErrorCode());
            }
        }
    }


    /**
     * <desc>
     *      将Excel中的当前行数据转换为对应的内存对象，并对文件中的数据基本格式进行检测
     * </desc>
     *
     * @param hssfRow       excel的一行
     * @param dataFormatter excel单元格操作对象
     * @return 导入/导出的地址文件Excel(*.xls)中的单行地址信息对象
     * @author LewisLouis
     * @createDate 2017-10-20
     */
    private PropertyProjectAddressRowDTO excelRowToAddressInfo(Row hssfRow, DataFormatter dataFormatter) {

        //创建Excel中的行数据对应的地址内存对象
        PropertyProjectAddressRowDTO propertyProjectAddressRowDTO = new PropertyProjectAddressRowDTO();
        //错误信息列表
        List<ErrorCode> errorCodes = propertyProjectAddressRowDTO.getErrorCodes();

        //首先登记所属的Sheet名称和行号
        propertyProjectAddressRowDTO.setSheetName(hssfRow.getSheet().getSheetName());
        propertyProjectAddressRowDTO.setRowNum(hssfRow.getRowNum() + 1);

        //处理楼栋名称
        String buildName = dataFormatter.formatCellValue(hssfRow.getCell(0));
        if (StringUtils.isNotBlank(buildName)){
            buildName = buildName.trim();
        }
        if (StringUtils.isBlank(buildName)) {
            errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NAME_EMPTY_ERR.getErrorCode());
        }
        if (buildName.length() > PlatformConstants.MAX_BUILD_NAME_LENGTH) {
            errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NAME_LENGTH_ERR.getErrorCode());
        }
        if(StringHandlerUtil.containsEmoji(buildName)){
            errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NAME_CONTAIN_EMOJI_ERR.getErrorCode());
        }
        propertyProjectAddressRowDTO.setBuildName(buildName);

        // 处理楼栋编号
        String buildNum = dataFormatter.formatCellValue(hssfRow.getCell(1));
        if (StringUtils.isNotBlank(buildNum)) { // 若楼栋编号不为空，则先判断楼栋编号的合法性，处理楼栋编号格式，前置补0
            buildNum = buildNum.trim();
            int intBuildNum = StringHandlerUtil.strToIntDef(buildNum, 0);
            if (!NumberHandlerUtil.isInRange(intBuildNum,PlatformConstants.MIN_BUILD_NUM,PlatformConstants.MAX_BUILD_NUM)){
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_BUILD_NUM_INVALID_ERR.getErrorCode());
            } else {
                buildNum = StringHandlerUtil.formatStrLen(buildNum, "0", 3, false, false);
                propertyProjectAddressRowDTO.setBuildNum(buildNum);
            }
        }


        //处理单元名称
        String unitName = dataFormatter.formatCellValue(hssfRow.getCell(2));
        if (StringUtils.isNotBlank(unitName)){
            unitName = unitName.trim();
        }
        if (StringUtils.isBlank(unitName)) {
            errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NAME_EMPTY_ERR.getErrorCode());
        } else {
            if (unitName.length() > PlatformConstants.MAX_UNIT_NAME_LENGTH) {
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NAME_LENGTH_ERR.getErrorCode());
            }
            if (StringHandlerUtil.containsEmoji(unitName)){
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NAME_CONTAIN_EMOJI_ERR.getErrorCode());
            }
        }

        propertyProjectAddressRowDTO.setUnitName(unitName);

        // 处理单元编号
        String unitNum = dataFormatter.formatCellValue(hssfRow.getCell(3));
        if (StringUtils.isNotBlank(unitNum)) { // 若单元编号不为空，则判断其合法性
            unitNum = unitNum.trim();
            int intUnitNum = StringHandlerUtil.strToIntDef(unitNum, 0);
            if (!NumberHandlerUtil.isInRange(intUnitNum,PlatformConstants.MIN_UNIT_NUM,PlatformConstants.MAX_UNIT_NUM)){
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_NUM_INVALID_ERR.getErrorCode());
            } else {
                unitNum = StringHandlerUtil.formatStrLen(unitNum,"0",2,false,false);
                propertyProjectAddressRowDTO.setUnitNum(unitNum);
            }
        }

        //处理楼栋单元代号
        String unitAlias = dataFormatter.formatCellValue(hssfRow.getCell(4));
        if (StringUtils.isNotBlank(unitAlias)){
            unitAlias = unitAlias.trim();
        }
        if (!StringUtils.isBlank(unitAlias)) {
            Integer intUnitAlias = StringHandlerUtil.strToIntDef(unitAlias, 0);
            if (!NumberHandlerUtil.isInRange(intUnitAlias, PlatformConstants.MIN_UNIT_ALIAS, PlatformConstants.MAX_UNIT_ALIAS)) {
                //楼栋单元代号非法
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_UNIT_ALIAS_INVALID_ERR.getErrorCode());
            }
        }
        propertyProjectAddressRowDTO.setUnitAlias(unitAlias);

        //处理房间编号
        String roomNum = dataFormatter.formatCellValue(hssfRow.getCell(5));
        if (StringUtils.isNotBlank(roomNum)){
            roomNum = roomNum.trim();
        }
        Integer intRoomNum = StringHandlerUtil.strToIntDef(roomNum, -1);
        if (intRoomNum != 0){  //房间号和访客呼叫码若同时为0时，房间号可为0
            if (!NumberHandlerUtil.isInRange(intRoomNum, PlatformConstants.MIN_ROOM_NUM, PlatformConstants.MAX_ROOM_NUM)) {
                //房间编号非法
                errorCodes.add(PropertyErrorCodeEnum.PROJECT_ROOM_NUM_INVALID_ERR.getErrorCode());
            }
        }

        propertyProjectAddressRowDTO.setRoomNum(roomNum);

        // 处理建筑面积
        String builtArea = dataFormatter.formatCellValue(hssfRow.getCell(6));
        if (StringUtils.isBlank(builtArea)) {
            errorCodes.add(PropertyErrorCodeEnum.ROOM_BUILT_AREA_EMPTY_ERR.getErrorCode());
        } else {
            builtArea = builtArea.trim();
            if (!builtArea.matches("^([1-9][0-9]{0,7}|0)(\\.\\d{1,2})?$")) {
                errorCodes.add(PropertyErrorCodeEnum.ROOM_BUILT_AREA_INVALID_ERR.getErrorCode());
            }
        }
        propertyProjectAddressRowDTO.setBuiltArea(builtArea);

        //处理访客呼叫码（即房间呼叫代号）
        String roomAlias = dataFormatter.formatCellValue(hssfRow.getCell(7));
        if (StringUtils.isNotBlank(roomAlias)){
            roomAlias = roomAlias.trim();
        }
        if ((intRoomNum == 0) && (StringUtils.isBlank(roomAlias))){
            roomAlias = PlatformConstants.CENTER_CALL_CODE;
        }
        Integer intRoomAlias = -1;
        if (!StringUtils.isBlank(roomAlias)) {
            intRoomAlias = StringHandlerUtil.strToIntDef(roomAlias, -1);
            if (intRoomAlias != 0){
                if (!NumberHandlerUtil.isInRange(intRoomAlias, PlatformConstants.MIN_ROOM_ALIAS, PlatformConstants.MAX_ROOM_ALIAS)) {
                    //访客呼叫码非法
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_ROOM_ALIAS_INVALID_ERR.getErrorCode());
                }
            } else {
                if (intRoomNum != 0) {
                    errorCodes.add(PropertyErrorCodeEnum.PROJECT_ZERO_ROOM_ALIAS_INVALID_ERR.getErrorCode());
                }
            }
        }

        if ((intRoomNum == 0) && (intRoomAlias != 0)){
            errorCodes.add(PropertyErrorCodeEnum.PROJECT_ZERO_ROOM_NUM_INVALID_ERR.getErrorCode());
        }

        if (intRoomAlias == 0){
            roomAlias = PlatformConstants.CENTER_CALL_CODE;
        } else    //自动消去房屋被呼号码可能的前置0，如 "0301"->"301", "00301"->"301"
        {
            if (StringUtils.isNotBlank(roomAlias)){
                roomAlias = roomAlias.replaceAll("^(0+)", "");
            }
        }
        propertyProjectAddressRowDTO.setRoomAlias(roomAlias);

        //处理正背门
        String liftDoorTypeName = dataFormatter.formatCellValue(hssfRow.getCell(8));
        if (StringUtils.isNotBlank(liftDoorTypeName)){
            liftDoorTypeName = liftDoorTypeName.trim();
        }
        Integer liftDoorType = LiftDoorTypeEnum.getType(liftDoorTypeName);
        propertyProjectAddressRowDTO.setLiftDoorType(liftDoorType);

        //处理备注
        String remark = dataFormatter.formatCellValue(hssfRow.getCell(9));
        if (StringUtils.isNotBlank(remark)){
            remark = remark.trim();
        }
        if ((!StringUtils.isBlank(remark)) && (remark.length() > PlatformConstants.MAX_ROOM_REMARK_LENGTH)) {
            //房间备注非法
            errorCodes.add(PropertyErrorCodeEnum.PROJECT_ROOM_REMARK_LENGTH_ERR.getErrorCode());
        }
        if (!StringUtils.isBlank(remark) && StringHandlerUtil.containsEmoji(remark)){
            errorCodes.add(PropertyErrorCodeEnum.PROJECT_REMARK_CONTAIN_EMOJI_ERR.getErrorCode());
        }
        propertyProjectAddressRowDTO.setRemark(remark);

        return propertyProjectAddressRowDTO;
    }

    /**
     * <desc>
     *      根据房间编号获取楼层号.
     * </desc>
     *
     * @param roomNum 房间编号
     * @return 楼层号
     * @author LewisLouis
     * @createDate 2017-10-13
     */
    private int getFloorNoByRoomNum(String roomNum) {
        String floorInfo = StringHandlerUtil.copySubStr(roomNum, 0, 2);
        return StringHandlerUtil.strToIntDef(floorInfo, 0);
    }


    /**
     * <desc>
     *      根据楼栋名称获取数据库中的楼栋信息.
     * </desc>
     *
     * @param buildName        楼栋名称
     * @param buildInfoVOSInDB 当前项目数据库中的楼栋信息列表
     * @return 楼栋信息
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private PropertyProjectBuildInfoVO getBuildDBInfoByName(String buildName, List<PropertyProjectBuildInfoVO> buildInfoVOSInDB) {
        for (PropertyProjectBuildInfoVO propertyProjectBuildInfoVO : buildInfoVOSInDB) {
            if (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectBuildInfoVO.getBuildName(), buildName)) {
                return propertyProjectBuildInfoVO;
            }
        }
        return null;
    }

    /**
     * <desc>
     *      获取最小可用楼栋编号(buildNum).
     * </desc>
     *
     * @param buildsInFile                    文件中已找到的楼栋列表
     * @param propertyProjectBuildInfoInDBVOS 数据库中的楼栋列表
     * @return 最小可用楼栋编号(buildNum).
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private int getMinAvailableBuildNum(Map<String, PropertyProjectImportBuildInfoDTO> buildsInFile,
                                        List<PropertyProjectBuildInfoVO> propertyProjectBuildInfoInDBVOS) {
        int minBuildNum = PlatformConstants.MIN_BUILD_NUM;
        // int buildNum;
        String oneBuildNum;
        boolean hasFind;

        //从最小楼栋编号到最大楼栋编号,依次遍历,检查楼栋编号是否已使用，若未使用，则直接返回
        for (int buildIndex = PlatformConstants.MIN_BUILD_NUM;
             buildIndex <= PlatformConstants.MAX_BUILD_NUM; buildIndex++ )
        {
            oneBuildNum = NumberHandlerUtil.numFormatToString(buildIndex,3);
            hasFind = false;
            //遍历数据库中的所有楼栋信息，检测该楼栋号是否使用
            for (PropertyProjectBuildInfoVO propertyProjectBuildInfoVO : propertyProjectBuildInfoInDBVOS) {
                if (StringHandlerUtil.compareStrWithOutEmpty(oneBuildNum,propertyProjectBuildInfoVO.getBuildNum()))
                {
                    hasFind = true;
                    break;
                }
            }
            if (hasFind){
                continue;
            }
            //遍历已处理的来自于文件中的楼栋信息，检测该楼栋号是否使用
            for (Map.Entry<String, PropertyProjectImportBuildInfoDTO> entry : buildsInFile.entrySet()) {
                PropertyProjectImportBuildInfoDTO propertyProjectImportBuildInfoDTO = entry.getValue();
                if (StringHandlerUtil.compareStrWithOutEmpty(oneBuildNum,propertyProjectImportBuildInfoDTO.getBuildNum()))
                {
                    hasFind = true;
                    break;
                }
            }

            if (!hasFind){
                minBuildNum = buildIndex;
                break;
            }
            minBuildNum = buildIndex + 1;
        }
        return  minBuildNum;
    }


    /**
     * <desc>
     *      获取指定楼栋下的最小可用单元编号(UnitNum).
     * </desc>
     *
     * @param unitsInOneBuild                    文件中已找到该楼栋下的单元
     * @param buildName                          楼栋名称
     * @param propertyProjectUnitInfoInDBVOSInDB 数据库中所有的单元列表
     * @return 最小可用单元编号(UnitNum).
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private int getMinAvailableUnitNum(Map<String, PropertyProjectImportUnitInfoDTO> unitsInOneBuild, String buildName,
                                       List<PropertyProjectUnitInfoVO> propertyProjectUnitInfoInDBVOSInDB) {
        List<PropertyProjectUnitInfoVO> propertyProjectUnitInfoInOneBuildInDBVOS = getUnitsInOneBuildInDB(buildName,
                propertyProjectUnitInfoInDBVOSInDB);
        int minUnitNum = PlatformConstants.MIN_UNIT_NUM;
        int unitNum;
        Set<Integer> unitNumSet = new HashSet<>();
        for (PropertyProjectUnitInfoVO propertyProjectUnitInfoVO : propertyProjectUnitInfoInOneBuildInDBVOS) {
            unitNumSet.add(StringHandlerUtil.strToIntDef(propertyProjectUnitInfoVO.getUnitNum(), 0));
        }
        for (Map.Entry<String, PropertyProjectImportUnitInfoDTO> entry : unitsInOneBuild.entrySet()) {
            PropertyProjectImportUnitInfoDTO propertyProjectImportUnitInfoDTO = entry.getValue();
            unitNumSet.add(StringHandlerUtil.strToIntDef(propertyProjectImportUnitInfoDTO.getUnitNum(), 0));
        }

        //遍历数据库中的当前楼栋下的单元信息，取最小单元编号
        for (int i = PlatformConstants.MIN_UNIT_NUM; i <= PlatformConstants.MAX_UNIT_NUM; i++ ) {
            if (!unitNumSet.contains(minUnitNum)) {
                break;
            }
            minUnitNum ++;
//            unitNum = StringHandlerUtil.strToIntDef(propertyProjectUnitInfoVO.getUnitNum(), 0);
//            if (unitNum >= minUnitNum) {
//                minUnitNum = unitNum + 1;
//            }
        }

        //遍历已处理的来自于文件中的当前楼栋下的单元信息，取最小单元编号
//        for (Map.Entry<String, PropertyProjectImportUnitInfoDTO> entry : unitsInOneBuild.entrySet()) {
//            if (!unitNumSet.contains(minUnitNum)) {
//                break;
//            }
//            PropertyProjectImportUnitInfoDTO propertyProjectImportUnitInfoDTO = entry.getValue();
//            unitNum = StringHandlerUtil.strToIntDef(propertyProjectImportUnitInfoDTO.getUnitNum(), 0);
//            if (unitNum >= minUnitNum) {
//                minUnitNum = unitNum + 1;
//            }
//        }
        return minUnitNum;
    }

    /**
     * <desc>
     *      获取指定项目下的最小可用单元代号(UnitAlias).
     * </desc>
     *
     * @param propertyProjectSaveImportAddressDTO   从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     *  @param buildName 楼栋名称
     * @param unitName 单元名称
     * @return 最小可用单元代号(UnitAlias).
     * @author LewisLouis
     * @createDate 2017-12-15
     */
    private String getMinAvaliableUnitAlias(PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO,
                                            String buildName,String unitName, String buildNum, String unitNum){

        Map<String, PropertyProjectImportBuildInfoDTO> buildsInFile = propertyProjectSaveImportAddressDTO.getAddressInfosInFile();
        List<PropertyProjectUnitInfoVO> propertyProjectUnitInfoInDBVOSInDB = propertyProjectSaveImportAddressDTO.getUnitInfoVOSInDB();
        //首先按默认规则生成单元代号，若未被使用，则直接返回
        String defaultUnitAlias = String.format("%s%s",buildNum,unitNum);
        if(!checkUnitAliasExists(buildName,unitName,defaultUnitAlias,propertyProjectSaveImportAddressDTO)){
            //自动消去楼栋单元代号可能的前置0，如 "0301"->"301", "00301"->"301"
            defaultUnitAlias = defaultUnitAlias.replaceAll("^(0+)", "");
            return defaultUnitAlias;
        }
        int minUnitAlias = PlatformConstants.MIN_UNIT_ALIAS;
        int unitAlias;

        //遍历数据库中的当前项目下的单元信息，取最小单元代号
        for (PropertyProjectUnitInfoVO propertyProjectUnitInfoVO : propertyProjectUnitInfoInDBVOSInDB) {
            unitAlias = StringHandlerUtil.strToIntDef(propertyProjectUnitInfoVO.getUnitAlias(), 0);
            if (unitAlias <= minUnitAlias) {
                minUnitAlias = unitAlias + 1;
            }
        }

        //遍历已处理的来自于文件中的当前项目下的单元信息，取最小单元编号
        for (Map.Entry<String, PropertyProjectImportBuildInfoDTO> buidEntry : buildsInFile.entrySet()) {
            PropertyProjectImportBuildInfoDTO propertyProjectImportBuildInfoDTO = buidEntry.getValue();
            for (Map.Entry<String, PropertyProjectImportUnitInfoDTO> unitEntry : propertyProjectImportBuildInfoDTO.getUnitsInFile().entrySet()) {
                PropertyProjectImportUnitInfoDTO propertyProjectImportUnitInfoDTO = unitEntry.getValue();
                unitAlias = StringHandlerUtil.strToIntDef(propertyProjectImportUnitInfoDTO.getUnitAlias(), 0);
                if (unitAlias <= minUnitAlias) {
                    minUnitAlias = unitAlias + 1;
                }
            }

        }
        return String.valueOf(minUnitAlias);
    }


    /**
     * <desc>
     *      获取在数据库中的指定楼栋下的单元列表
     * </desc>
     *
     * @param buildName                      楼栋名称
     * @param propertyProjectUnitInfoInDBVOS 数据库中当前项目到所有单元列表
     * @return 单元列表
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private List<PropertyProjectUnitInfoVO> getUnitsInOneBuildInDB(String buildName,
                                                                   List<PropertyProjectUnitInfoVO> propertyProjectUnitInfoInDBVOS) {
        List<PropertyProjectUnitInfoVO> propertyProjectUnitInfoVOS = new ArrayList<>();
        for (PropertyProjectUnitInfoVO propertyProjectUnitInfoVO : propertyProjectUnitInfoInDBVOS) {
            if (!StringHandlerUtil.compareStrWithOutEmpty(propertyProjectUnitInfoVO.getBuildName(), buildName)) {
                continue;
            }
            propertyProjectUnitInfoVOS.add(propertyProjectUnitInfoVO);
        }
        return propertyProjectUnitInfoVOS;
    }


    /**
     * <desc>
     *      根据楼栋名称和单元名称获取数据库中的单元信息.
     * </desc>
     *
     * @param buildName       楼栋名称
     * @param unitName        单元名称
     * @param unitInfoVOSInDB 当前项目数据库中的单元信息列表
     * @return 单元信息
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private PropertyProjectUnitInfoVO getUnitDBInfoByName(String buildName, String unitName, List<PropertyProjectUnitInfoVO> unitInfoVOSInDB) {
        for (PropertyProjectUnitInfoVO propertyProjectUnitInfoVO : unitInfoVOSInDB) {
            if ((StringHandlerUtil.compareStrWithOutEmpty(propertyProjectUnitInfoVO.getBuildName(), buildName))
                    && (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectUnitInfoVO.getUnitName(), unitName))) {
                return propertyProjectUnitInfoVO;
            }
        }
        return null;
    }

    /**
     * <desc>
     *      检查单元代号存在性(项目内唯一)
     * </desc>
     *
     * @param unitAlias                           单元代号
     * @param unitName                            单元名称
     * @param propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @return True 已存在 false 不存在
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private boolean checkUnitAliasExists(String buildName, String unitAlias, String unitName,
                                         PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO) {

        //当前项目中数据库中已有的单元信息
        List<PropertyProjectUnitInfoVO> unitInfoVOSInDB = propertyProjectSaveImportAddressDTO.getUnitInfoVOSInDB();
        for (PropertyProjectUnitInfoVO propertyProjectUnitInfoVO : unitInfoVOSInDB) {
            if ((!(StringHandlerUtil.compareStrWithOutEmpty(propertyProjectUnitInfoVO.getUnitName(), unitName)&&
                    StringHandlerUtil.compareStrWithOutEmpty(propertyProjectUnitInfoVO.getBuildName(), buildName))) &&
                    (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectUnitInfoVO.getUnitAlias(), unitAlias))) {
                return true;
            }
        }

        //导入文件中的单元列表<buildName,<unitName,PropertyProjectImportUnitInfoDTO>>
        Map<String, PropertyProjectImportBuildInfoDTO> buildInfoPOSInFile = propertyProjectSaveImportAddressDTO.getAddressInfosInFile();
        for (Map.Entry<String, PropertyProjectImportBuildInfoDTO> oneBuildEntry : buildInfoPOSInFile.entrySet()) {
            PropertyProjectImportBuildInfoDTO oneBuildInFile = oneBuildEntry.getValue();
            Map<String, PropertyProjectImportUnitInfoDTO> unitInfoPOSInOneBuildInFile = oneBuildInFile.getUnitsInFile();
            for (Map.Entry<String, PropertyProjectImportUnitInfoDTO> oneUnitEntry : unitInfoPOSInOneBuildInFile.entrySet()){
                PropertyProjectImportUnitInfoDTO oneUnitInFile = oneUnitEntry.getValue();
                if ((!(StringHandlerUtil.compareStrWithOutEmpty(oneUnitInFile.getUnitName(), unitName)
                        && StringHandlerUtil.compareStrWithOutEmpty(oneBuildInFile.getBuildName(), buildName))) &&
                        (StringHandlerUtil.compareStrWithOutEmpty(oneUnitInFile.getUnitAlias(), unitAlias))) {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * <desc>
     *      获取数据库中当前项目下的所有楼栋列表
     * </desc>
     *
     * @param projectId 项目编号
     * @return 楼栋信息列表
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private List<PropertyProjectBuildInfoVO> getBuildInfoFromDB(String projectId) throws Exception {
        PropertyProjectGetBuildInfoDTO propertyProjectGetBuildInfoDTO = new PropertyProjectGetBuildInfoDTO();
        propertyProjectGetBuildInfoDTO.setProjectId(projectId);
        propertyProjectGetBuildInfoDTO.setCurrentPage("1");
        propertyProjectGetBuildInfoDTO.setPageSize(String.valueOf(PlatformConstants.MAX_BUILD_NUM));
        Page<PropertyProjectBuildInfoVO> propertyProjectBuildInfoVOPage = iPropertyBuildInfoServiceClient.getPage(propertyProjectGetBuildInfoDTO);
        return propertyProjectBuildInfoVOPage.getRows();
    }


    /**
     * <desc>
     *      获取数据库中当前项目下的所有单元列表
     * </desc>
     *
     * @param projectId 项目编号
     * @return 单元信息列表
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private List<PropertyProjectUnitInfoVO> getUnitInfoFromDB(String projectId) throws Exception {
        PropertyProjectGetUnitInfoDTO propertyProjectGetUnitInfoDTO = new PropertyProjectGetUnitInfoDTO();
        propertyProjectGetUnitInfoDTO.setProjectId(projectId);
        propertyProjectGetUnitInfoDTO.setCurrentPage("1");
        propertyProjectGetUnitInfoDTO.setPageSize(String.valueOf(PlatformConstants.MAX_UNIT_NUM * PlatformConstants.MAX_BUILD_NUM));
        Page<PropertyProjectUnitInfoVO> propertyProjectUnitInfoVOPage = iPropertyUnitInfoServiceClient.getPage(propertyProjectGetUnitInfoDTO);
        return propertyProjectUnitInfoVOPage.getRows();
    }

    /**
     * <desc>
     *      获取数据库中当前项目下的所有房间列表，在房屋数量较低时使用
     * </desc>
     *
     * @param projectId 项目编号
     * @return 房间信息列表
     * @author LewisLouis
     * @createDate 2017-11-29
     */
    private List<PropertyProjectRoomInfoVO> getRoomInfoFromDB(String projectId) throws Exception {
        PropertyProjectGetRoomInfoDTO propertyProjectGetRoomInfoDTO = new PropertyProjectGetRoomInfoDTO();
        propertyProjectGetRoomInfoDTO.setProjectId(projectId);
        propertyProjectGetRoomInfoDTO.setCurrentPage("1");
        propertyProjectGetRoomInfoDTO.setPageSize(String.valueOf(PlatformConstants.MAX_UNIT_NUM * PlatformConstants.MAX_BUILD_NUM * PlatformConstants.MAX_ROOM_NUM));
        Page<PropertyProjectRoomInfoVO> propertyProjectRoomInfoVOPage = iPropertyRoomInfoServiceClient.getPage(propertyProjectGetRoomInfoDTO);
        return propertyProjectRoomInfoVOPage.getRows();
    }

    /**
     * <desc>
     *      获取指定楼栋的房屋信息列表
     * </desc>
     *
     * @param wholeProjectPropertyProjectRoomInfoVOS 整个项目的房屋信息
     * @param buildId 楼栋Id
     * @return 指定楼栋的房屋信息列表
     * @author LewisLouis
     * @createDate 2017-11-29
     */
    private List<PropertyProjectRoomInfoVO> getRoomInfoInDBByBuildId(List<PropertyProjectRoomInfoVO> wholeProjectPropertyProjectRoomInfoVOS, String buildId) throws Exception {
        List<PropertyProjectRoomInfoVO> resultRoomList = new ArrayList<>();
        for (PropertyProjectRoomInfoVO propertyProjectRoomInfoVO:wholeProjectPropertyProjectRoomInfoVOS){
            if (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectRoomInfoVO.getBuildId(),buildId)){
                resultRoomList.add(propertyProjectRoomInfoVO);
            }
        }
        return resultRoomList;
    }



    /**
     * <desc>
     *    计算房屋数量.
     * </desc>
     *
     * @param  propertyProjectUnitInfoVOS  单元列表
     * @return 房屋数量
     * @author LewisLouis
     * @createDate 2017-11-29
     */
    private Integer getRoomCountInDB(List<PropertyProjectUnitInfoVO> propertyProjectUnitInfoVOS ){
        int roomCount = 0;
        for (PropertyProjectUnitInfoVO propertyProjectUnitInfoVO:propertyProjectUnitInfoVOS){
            roomCount += propertyProjectUnitInfoVO.getRoomCount();
        }
        return  roomCount;
    }



    /**
     * <desc>
     *      根据房屋编号和单元名称查找房屋信息.
     * </desc>
     *
     * @param roomNum                              房间编号
     * @param unitName                             单元名称
     * @param roomInfosInOneBuildInDB 当前楼栋下的所有房屋信息列表
     * @return 房屋信息，未找到返回Null
     * @author LewisLouis
     * @createDate 2017-10-16
     */
    private PropertyProjectRoomInfoVO getRoomInfoFromBuildInDBByRoomNum(String unitName, String roomNum,
                                                                        List<PropertyProjectRoomInfoVO> roomInfosInOneBuildInDB) {
        for (PropertyProjectRoomInfoVO propertyProjectRoomInfoVO : roomInfosInOneBuildInDB) {
            if ((StringHandlerUtil.compareStrWithOutEmpty(propertyProjectRoomInfoVO.getUnitName(), unitName))
                    && (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectRoomInfoVO.getRoomNum(), roomNum))) {
                return propertyProjectRoomInfoVO;
            }


        }
        return null;
    }


    /**
     * <desc>
     *      获取数据库中当前单元下的房屋列表.
     * </desc>
     *
     * @param  roomsInOneBuildInDB 当前楼栋下的房屋列表
     * @param  unitName 单元名称
     * @return 当前单元下的房屋列表.
     * @author LewisLouis
     * @createDate 2017-12-15
     */
    private  List<PropertyProjectRoomInfoVO> getRoomsInOneUnitInDB(List<PropertyProjectRoomInfoVO> roomsInOneBuildInDB, String unitName){
        List<PropertyProjectRoomInfoVO> roomsInOneUnitInDB = new ArrayList<>();
        for (PropertyProjectRoomInfoVO oneRoomInDB:roomsInOneBuildInDB){
            if (StringHandlerUtil.compareStrIgnoreCaseWithOutEmpty(oneRoomInDB.getUnitName(),unitName)){
                roomsInOneUnitInDB.add(oneRoomInDB);
            }
        }
        return roomsInOneUnitInDB;
    }

    /**
     * <desc>
     *      根据楼栋名称在数据库和已处理的楼栋信息列表中获取楼栋Id.
     * </desc>
     *
     * @param buildName                   楼栋名称
     * @param buildInfoPOInFileMap        已处理的楼栋信息
     * @param propertyProjectBuildInfoVOS 数据库中的楼栋信息列表
     * @return 楼栋Id，未找到则返回空字符串
     * @author LewisLouis
     * @createDate 2017-10-16
     */
    private String getBuildIdByBuildName(String buildName, Map<String, PropertyProjectImportBuildInfoDTO> buildInfoPOInFileMap,
                                         List<PropertyProjectBuildInfoVO> propertyProjectBuildInfoVOS) {

        //从数据库中的楼栋信息中根据楼栋编号查找楼栋Id
        for (PropertyProjectBuildInfoVO propertyProjectBuildInfoVO : propertyProjectBuildInfoVOS) {
            if (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectBuildInfoVO.getBuildName(), buildName)) {
                return propertyProjectBuildInfoVO.getBuildId();
            }
        }
        //从已导入的楼栋信息中根据楼栋编号查找楼栋Id
        for (Map.Entry<String, PropertyProjectImportBuildInfoDTO> buildInfoPOEntry : buildInfoPOInFileMap.entrySet()) {
            PropertyProjectImportBuildInfoDTO buildInfoPO = buildInfoPOEntry.getValue();
            if (StringHandlerUtil.compareStrWithOutEmpty(buildInfoPO.getBuildName(), buildName)) {
                return buildInfoPO.getBuildId();
            }
        }
        return "";
    }


    /**
     * <desc>
     *      检查访客呼叫码存在性（应单元内唯一）
     * </desc>
     *
     * @param roomNum       房间编号
     * @param roomAlias       访客呼叫码
     * @param roomInfoInOneUnitInDB 数据库中当前单元下的房屋信息列表
     * @param roomsInOneUnitInFile 文件中当前单元下的房屋信息列表
     * @return True 已存在 false 不存在
     * @author LewisLouis
     * @createDate 2017-10-19
     */
    private boolean checkRoomAliasExists(String roomNum, String roomAlias,
                                         List<PropertyProjectRoomInfoVO> roomInfoInOneUnitInDB,
                                         Map<String, PropertyProjectImportRoomInfoDTO> roomsInOneUnitInFile) {

        //导入的文件中是否存在其它房间的访客呼叫码与当前房间一致
        for (Map.Entry<String, PropertyProjectImportRoomInfoDTO> propertyProjectImportRoomInfoDTOEntry : roomsInOneUnitInFile.entrySet()) {
            PropertyProjectImportRoomInfoDTO propertyProjectImportRoomInfoDTO = propertyProjectImportRoomInfoDTOEntry.getValue();
            if ((!StringHandlerUtil.compareStrWithOutEmpty(propertyProjectImportRoomInfoDTO.getRoomNum(), roomNum))
                    && (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectImportRoomInfoDTO.getRoomAlias(), roomAlias))) {
                return true;
            }
        }

        //数据库是否存在其它房间的访客呼叫码与当前房间一致
        for (PropertyProjectRoomInfoVO propertyProjectRoomInfoVO : roomInfoInOneUnitInDB) {
            if ((!StringHandlerUtil.compareStrWithOutEmpty(propertyProjectRoomInfoVO.getRoomNum(), roomNum))
                    && (StringHandlerUtil.compareStrWithOutEmpty(propertyProjectRoomInfoVO.getRoomAlias(), roomAlias))) {
                return true;
            }
        }


        return false;
    }

    /**
     * <desc>
     *      获取指定单元下的最小可用访客呼叫码代号(RoomAlias).
     * </desc>
     *
     * @param roomInfoInOneUnitInDB  数据库中当前单元下的房屋信息列表
     * @param roomsInOneUnitInFile   导入文件中当前单元下的房屋信息列表
     * @param roomNum 房间号
     * @return 最小可用访客呼叫码代号(RoomAlias).
     * @author LewisLouis
     * @createDate 2017-12-15
     */
    private String getMinAvaliableRoomAlias(String roomNum,
                                            List<PropertyProjectRoomInfoVO> roomInfoInOneUnitInDB,
                                            Map<String, PropertyProjectImportRoomInfoDTO> roomsInOneUnitInFile){

        //首先按默认规则生成访客呼叫码，若未被使用，则直接返回
        String defaultRoomAlias = roomNum; //String.format("%s%s",buildNum,unitNum);
        if(!checkRoomAliasExists(roomNum,defaultRoomAlias,roomInfoInOneUnitInDB,roomsInOneUnitInFile)){
            defaultRoomAlias = defaultRoomAlias.replaceAll("^(0+)", "");
            return defaultRoomAlias;
        }
        int minRoomAlias = PlatformConstants.MIN_ROOM_ALIAS;
        int roomAlias;

        //遍历数据库中的当前单元下的单元信息，取最小访客呼叫码
        for (PropertyProjectRoomInfoVO propertyProjectRoomInfoVO : roomInfoInOneUnitInDB) {
            roomAlias = StringHandlerUtil.strToIntDef(propertyProjectRoomInfoVO.getRoomAlias(), 0);
            if (roomAlias <= minRoomAlias) {
                minRoomAlias = roomAlias + 1;
            }
        }

        //遍历已处理的来自于文件中的当前项目下的单元信息，取最小单元编号

        for (Map.Entry<String, PropertyProjectImportRoomInfoDTO> roomEntry : roomsInOneUnitInFile.entrySet()) {
            PropertyProjectImportRoomInfoDTO propertyProjectImportRoomInfoDTO = roomEntry.getValue();
            roomAlias = StringHandlerUtil.strToIntDef(propertyProjectImportRoomInfoDTO.getRoomAlias(), 0);
            if (roomAlias <= minRoomAlias) {
                minRoomAlias = roomAlias + 1;
            }
        }
        return String.valueOf(minRoomAlias);
    }


    /**
     * <desc>
     *    判断楼栋ID是否已经在数据库中.
     * </desc>
     *
     * @param  propertyProjectSaveImportAddressDTO 从Excel(*.xls)导入地址信息数据传输对象(含楼栋列表、单元列表、房间列表,用于保存到数据库)
     * @param buildId 楼栋Id
     * @return true 存在  false 不存在
     * @author LewisLouis
     * @createDate 2017-11-29
     */
    private  boolean checkBuildIdInDB(PropertyProjectSaveImportAddressDTO propertyProjectSaveImportAddressDTO, String buildId){
        List<PropertyProjectBuildInfoVO> buildInfoVOS = propertyProjectSaveImportAddressDTO.getBuildInfoVOSInDB();
        for (PropertyProjectBuildInfoVO propertyProjectBuildInfoVO:buildInfoVOS){
            if (StringHandlerUtil.compareStrWithOutEmpty(buildId,propertyProjectBuildInfoVO.getBuildId()))
            {
                return true;
            }
        }
        return false;
    }
    /**
     * <desc>
     *    Ftp上传文件，返回Url.
     * </desc>
     *
     * @param inputStream 文件流
     * @return 文件上传成功后会返回Url,否则返回空
     * @author LewisLouis
     * @createDate 2017-11-28
     */
    public String uploadFile(InputStream inputStream, String fileName) throws IOException {

        String fileUrl = "";
        String fileType = StringHandlerUtil.copySubStr(fileName, fileName.lastIndexOf('.'), fileName.length());
        UploadFileUtil.UploadFile uploadFileUtil = new UploadFileUtil().new UploadFile(
                FILE_FTP_HOST,
                FILE_FTP_USERNAME,
                FILE_FTP_PASSWORD,
                FILE_FTP_PORT,
                inputStream,
                fileType,
                FILE_ACCESS_URL,
                FileCatalogEnum.ADDRESSTEMPLATE_FILE.getType()
        );
        Map<String, Object> resultMap = UploadFileUtil.uploadFile(uploadFileUtil);
        Boolean returnCode = (Boolean)resultMap.get("returnCode");
        if (returnCode == false){
            return fileUrl;
        }
        fileUrl = resultMap.get("accessPath").toString();
        return fileUrl;
    }


    /**
     * <desc>
     *     向错误列表中增加有错误的地址信息.
     * </desc>
     *
     * @param  errorImportDataList 错误列表
     * @param  newAddressInfo 有错误的地址信息
     * @author LewisLouis
     * @createDate 2017-12-13
     */
    private void addErrorAddressInfoToList(List<PropertyProjectAddressRowDTO> errorImportDataList,
                                           PropertyProjectAddressRowDTO newAddressInfo){
        for (PropertyProjectAddressRowDTO oneAddressInfo:errorImportDataList){
            if ((oneAddressInfo.getRowNum() ==  newAddressInfo.getRowNum())
                    && (StringHandlerUtil.compareStrWithOutEmpty(oneAddressInfo.getSheetName(),newAddressInfo.getSheetName()))){
                return;
            }
        }
        errorImportDataList.add(newAddressInfo);
    }



}
